package com.gmall.cart.service;


import com.gmall.common.result.Result;
import com.gmall.model.cart.CartInfo;
import com.gmall.model.page.PageResult;
import com.gmall.model.product.SkuInfo;
import com.gmall.product.feign.ProductApiFeignClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class CartService {

    //为什么Autowired RedisTemplate就可以直接使用？
    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    ProductApiFeignClient productApiFeignClient;

    public static final String REDIS_CART_PREFIX = "cartList:";
    public static final String REDIS_CART_PRICE_PREFIX = "cartList_price:";
    public static final String REDIS_CART_UPDATETIME_PREFIX = "cartList_updatetime:";
    /**
     * redis String,Hash,List,Set,Zset
     * Hash 大Key cartList:userId
     *            小Key：skuId，value:cartInfo
     *       cartList:1
     *            19      cartInfo（加入购物车时的SKU信息）
     *            20      cartInfo（加入购物车时的SKU信息）
     *       cartList:4
     *            19      cartInfo（加入购物车时的SKU信息）
     *            20      cartInfo（加入购物车时的SKU信息）
     * @param userId
     * @param skuId
     * @param skuNum
     */
    public Result<String> addToCart(Long userId, Long skuId, Integer skuNum) {

        Boolean hasCart = redisTemplate.hasKey(REDIS_CART_PREFIX + userId);//大Key，该用户是否有购物车

        if(hasCart){
            CartInfo cartInfo = (CartInfo)redisTemplate.opsForHash().get(REDIS_CART_PREFIX + userId, skuId.toString());
            if(cartInfo!=null){//有，合并购物车
                cartInfo.setSkuNum(cartInfo.getSkuNum()+skuNum);
                cartInfo.setUpdateTime(new Date());//更新时间
                redisTemplate.opsForHash().put(REDIS_CART_PREFIX + userId, skuId.toString(), cartInfo);
                redisTemplate.opsForZSet().add(REDIS_CART_PRICE_PREFIX + userId, skuId.toString(), cartInfo.getCartPrice().doubleValue());
                redisTemplate.opsForZSet().add(REDIS_CART_UPDATETIME_PREFIX + userId, skuId.toString(), cartInfo.getUpdateTime().getTime());
                return Result.ok("购物车合并更新成功");
            }
        }
        CartInfo cartInfo = new CartInfo();
        cartInfo.setUserId(userId.toString());
        cartInfo.setSkuId(skuId);
        cartInfo.setSkuNum(skuNum);
        Date now = new Date();
        cartInfo.setCreateTime(now);//创建时间
        cartInfo.setUpdateTime(now);//更新时间
        Result<SkuInfo> result_skuInfo = productApiFeignClient.getSkuInfoById(skuId);
        if(result_skuInfo.isOk()){
            SkuInfo skuInfo = result_skuInfo.getData();
            cartInfo.setCartPrice(skuInfo.getPrice());//
            cartInfo.setSkuName(skuInfo.getSkuName());
            cartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
            cartInfo.setSkuPrice(skuInfo.getPrice());
        }
        redisTemplate.opsForHash().put(REDIS_CART_PREFIX + userId, skuId.toString(), cartInfo);
        redisTemplate.opsForZSet().add(REDIS_CART_PRICE_PREFIX + userId, skuId.toString(), cartInfo.getCartPrice().doubleValue());
        redisTemplate.opsForZSet().add(REDIS_CART_UPDATETIME_PREFIX + userId, skuId.toString(), cartInfo.getUpdateTime().getTime());
        return Result.ok("购物车添加成功");
    }

    public Result<List<CartInfo>> cartList(Long userId) {

        List<CartInfo> values = (List<CartInfo>)redisTemplate.opsForHash().values(REDIS_CART_PREFIX + userId);
        return Result.ok(values);
    }

    public Result<String> deleteCart(Long userId, Long skuId) {
        redisTemplate.opsForHash().delete(REDIS_CART_PREFIX + userId, skuId.toString());
        redisTemplate.opsForZSet().remove(REDIS_CART_PRICE_PREFIX + userId, skuId.toString());
        redisTemplate.opsForZSet().remove(REDIS_CART_UPDATETIME_PREFIX + userId, skuId.toString());
        return Result.ok("删除成功");
    }

    public Result<PageResult<CartInfo>> cartPage(Long userId, Integer pageNo, Integer pageSize, Map sortFieldMap) {

        String sortField = "price";
        String sortOrder = "desc";
        List<CartInfo> records = new ArrayList<>();

        if(sortFieldMap!=null){
            String _sortFiled = (String)sortFieldMap.get("sortField");
            if(_sortFiled!=null){
                sortField = _sortFiled;
            }
            String _sortOrder = (String)sortFieldMap.get("sortOrder");
            if(_sortOrder!=null){
                sortOrder = _sortOrder;
            }
        }
        Long total = 0L;
        Set skuIds = new HashSet();
        if(sortField.equalsIgnoreCase("price")){
            if(sortOrder.equalsIgnoreCase("asc")){
                skuIds = redisTemplate.opsForZSet().range(REDIS_CART_PRICE_PREFIX + userId,
                        (pageNo - 1) * pageSize, pageNo * pageSize - 1);
            }else{
                skuIds = redisTemplate.opsForZSet().reverseRange(REDIS_CART_PRICE_PREFIX + userId,
                        (pageNo - 1) * pageSize, pageNo * pageSize - 1);
            }
            total = redisTemplate.opsForZSet().size(REDIS_CART_PRICE_PREFIX + userId);
        }else if(sortField.equalsIgnoreCase("updatetime")){
            if(sortOrder.equalsIgnoreCase("asc")){
                skuIds = redisTemplate.opsForZSet().range(REDIS_CART_UPDATETIME_PREFIX + userId,
                        (pageNo - 1) * pageSize, pageNo * pageSize - 1);
            }else{
                skuIds = redisTemplate.opsForZSet().reverseRange(REDIS_CART_UPDATETIME_PREFIX + userId,
                        (pageNo - 1) * pageSize, pageNo * pageSize - 1);
            }
            total = redisTemplate.opsForZSet().size(REDIS_CART_UPDATETIME_PREFIX + userId);
        }

        skuIds.forEach(skuId->{
            CartInfo cartInfo = (CartInfo)redisTemplate.opsForHash().get(REDIS_CART_PREFIX + userId, skuId.toString());
            records.add(cartInfo);
        });

        PageResult<CartInfo> cartInfoPageResult = new PageResult<>(pageNo,pageSize);

        cartInfoPageResult.setRecords(records);
        cartInfoPageResult.setTotal(total);
        return Result.ok(cartInfoPageResult);
    }
}
